﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Web.UI.Design;
using System.ComponentModel;

namespace TR0217.ControlEx
{
    [ToolboxBitmap(typeof(MultiLabel), "MultiLabel.bmp")]
    public class MultiLabel : Label
    {
        public MultiLabel()
        {
            SetStyle(
                ControlStyles.OptimizedDoubleBuffer |
                ControlStyles.AllPaintingInWmPaint , true);

            this.SetStyle(ControlStyles.Selectable, false);
            this.SetStyle(ControlStyles.StandardClick, true);
            this.SetStyle(ControlStyles.StandardDoubleClick, true);
            this.UpdateStyles();

            this.PartCheckedChanged += new PartCheckHandler(MultiLabel_PartCheckedChanged);
        }

        void MultiLabel_PartCheckedChanged(object sender, PartCheckEventArgs e)
        {
            if (e.Checked)
            {
                if (_radioStyle == RadioStyle.Internal)
                {
                    _radioStyle = RadioStyle.None;
                    for (int i = 0; i < _partCount; i++)
                    {
                        if (e.Index != i) CheckPart(i,false);
                    }
                    _radioStyle = RadioStyle.Internal;
                }
                else if (_radioStyle == RadioStyle.External)
                {
                    foreach (Control ctrl in Parent.Controls)
                    {
                        MultiLabel lbl = ctrl as MultiLabel;
                        if (lbl != null && lbl != this)
                        {
                            lbl.UnCheckAll();
                        }
                    }
                }
            }

        }

        public event PartClickHandler PartClick = null;
        public event PartCheckHandler PartCheckedChanged = null;

        public void UnCheckAll()
        {
            for (int i = 0; i < _partCount; i++)
            {
                CheckPart(i,false);
            }
        }

        public void CheckPart(int index,bool flag)
        {
            if (index < _partCount && index > -1)
            {
                if (_checked[index] != flag)
                {
                    _checked[index] = flag;
                    if (PartCheckedChanged != null)
                    {
                        PartCheckedChanged(this,
                            new PartCheckEventArgs(_parts[index], index,flag));
                    }
                    this.Invalidate();
                }
            }
        }

        Color _checkedColor = Color.FromArgb(0, 0, 255);
        public System.Drawing.Color CheckedColor
        {
            get { return _checkedColor; }
            set { _checkedColor = value; }
        }

        RadioStyle _radioStyle = RadioStyle.External;
        public RadioStyle RadioStyle
        {
            get { return _radioStyle; }
            set { _radioStyle = value; }
        }

        bool _checkOnClick = true;
        public bool CheckOnClick
        {
            get { return _checkOnClick; }
            set { _checkOnClick = value; }
        }

        private char _separatorChar='|';
        public char SeparatorChar
        {
            get { return _separatorChar; }
        }
        private float _separatorWidth;

        private string[] _parts = null;
        private bool[] _checked = null;
        private RectangleF[] _bounds = null;
        private bool _calc = true;
        private int _pos = -1;
        private int _partCount = 1;

        public int PartCount
        {
            get { return _partCount; }
        }

        protected override void OnTextChanged(EventArgs e)
        {
            base.OnTextChanged(e);
            _parts = this.Text.Split(_separatorChar);
            _partCount = _parts.Length;
            _bounds = new RectangleF[_partCount];
            _checked = new bool[_partCount];
        }

        protected override void OnPaintBackground(PaintEventArgs pevent)
        {
            base.OnPaintBackground(pevent);
            if (this.BackColor != Color.Transparent)
            {
                this.Parent.Invalidate(this.Region);
                Graphics g = pevent.Graphics;
                if (Parent != null)
                {
                    int index = Parent.Controls.GetChildIndex(this);

                    for (int i = Parent.Controls.Count - 1; i > index; i--)
                    {
                        Control c = Parent.Controls[i];
                        if (c.Bounds.IntersectsWith(Bounds) && c.Visible)
                        {
                            Bitmap bmp = new Bitmap(c.Width, c.Height, g);
                            c.DrawToBitmap(bmp, c.ClientRectangle);

                            g.TranslateTransform(c.Left - Left, c.Top - Top);
                            g.DrawImageUnscaled(bmp, Point.Empty);
                            g.TranslateTransform(Left - c.Left, Top - c.Top);
                            bmp.Dispose();
                        }
                    }
                }
            }
        }

        protected override void OnPaint(PaintEventArgs e)
        {    
            if (_calc)
            {
                SizeF sz = e.Graphics.MeasureString(this.Text, this.Font);
                _separatorWidth = sz.Width / this.Text.Length/5;

                float x = 0;
                for (int i = 0; i < _parts.Length; i++)
                {
                    sz = e.Graphics.MeasureString(_parts[i], this.Font);
                    _bounds[i].X = x;
                    _bounds[i].Y = 0;
                    _bounds[i].Width = sz.Width;
                    _bounds[i].Height = this.Height;
                    x += (_bounds[i].Width + _separatorWidth);
                }
            }

            if (this.Enabled)
            {
                SolidBrush brushFore = new SolidBrush(this.ForeColor);
                SolidBrush chkBrushFore = new SolidBrush(this.CheckedColor);
                for (int i = 0; i < _parts.Length; i++)
                {
                    if (_pos != i)
                    {
                        e.Graphics.DrawString(_parts[i], this.Font, _checked[i] ? chkBrushFore : brushFore, _bounds[i]);
                    }
                    else
                    {
                        Font font = new Font(this.Font, FontStyle.Underline);
                        e.Graphics.DrawString(_parts[i], font, _checked[i] ? chkBrushFore : brushFore, _bounds[i]);
                        font.Dispose();
                    }
                }
                brushFore.Dispose();
                chkBrushFore.Dispose();
            }
            else
            {
                StringFormat format = new StringFormat(StringFormatFlags.LineLimit);
                for (int i = 0; i < _parts.Length; i++)
                {
                    ControlPaint.DrawStringDisabled(e.Graphics, _parts[i], this.Font,
                        this.BackColor == Color.Transparent ? SystemColors.Control : this.BackColor,
                        _bounds[i], null);
                }
                format.Dispose();
            }
        }

        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            for (int i = 0; i < _parts.Length; i++)
            {
                if (_bounds[i].Contains(e.Location))
                {
                    _pos = i; break;
                }
            }
            this.Invalidate();
        }

        protected override void OnMouseLeave(EventArgs e)
        {
            _pos = -1;
            this.Invalidate();
        }

        protected override void OnMouseClick(MouseEventArgs e)
        {
            base.OnMouseClick(e);
            if (_pos!=-1)
            {
                if (_checkOnClick)
                    CheckPart(_pos,true);
                if (PartClick != null)
                    PartClick(this, new PartClickEventArgs(e, _parts[_pos], _pos));
            }
        }
    }

    public class PartClickEventArgs : MouseEventArgs
    {
        private string _text;
        public string Text
        {
            get { return _text; }
            set { _text = value; }
        }
        private int _index;
        public int Index
        {
            get { return _index; }
            set { _index = value; }
        }

        public PartClickEventArgs(MouseEventArgs e,string text,int index)
            :base(e.Button,e.Clicks,e.X,e.Y,e.Delta)
        {
            _index = index;
            _text = text;
        }
    }

    public class PartCheckEventArgs : EventArgs
    {
        private string _text;
        public string Text
        {
            get { return _text; }
            set { _text = value; }
        }
        private int _index;
        public int Index
        {
            get { return _index; }
            set { _index = value; }
        }
        private bool _checked;
        public bool Checked
        {
            get { return _checked; }
            set { _checked = value; }
        }

        public PartCheckEventArgs(string text, int index,bool flag)
        {
            _index = index;
            _text = text;
            _checked = flag;
        }
    }

    public enum RadioStyle
    {
        Internal,
        External,
        None
    }

    public delegate void PartClickHandler(object sender, PartClickEventArgs e);
    public delegate void PartCheckHandler(object sender, PartCheckEventArgs e);
}
